#include "device.h"
#include "component.h"

/* 调试打印接口 */
#define DBATTERY_LOG(format, ...) __OSAL_LOG("[dbattery.c] " C_LIGHT_BLUE format C_NONE, ##__VA_ARGS__)


/* 电池电量更新事件 */
#define EVENT_BATTERY_UPDATE (0X00000001)

#define VHW_IRQ_BAT vPIN_I11
#define VHW_IIC_BAT vIIC_0
#define IIC_ADDR_BAT 0x55

#define CMD_READ_BAT_INF 0x1A

/* 电池电量更新事件的处理周期 */
#define BATTERY_UPDATE_EVT_PROC_CYCLE (200)

#pragma pack(1)
typedef struct
{
    uint16_t temp_s;   //小电池温度
    uint16_t temp_b;   //大电池温度
    uint16_t vol_s;    //小电池电压
    uint16_t vol_b;    //大电池电压
    uint16_t bat_s;    //小电池电量
    uint16_t bat_b;    //大电池电量
    uint8_t status[2]; //电池状态信息
} Bat_Info_t;
#pragma pack()

static DbatteryMsg_t batMsg;

/**
  * @brief  crc8计算
  * @note   多项式0x07
  * @param  ptr：数据域
  * @param  len：数据长度
  * @return crc值
  */
static uint8_t crc8_cal(uint8_t *ptr, uint16_t len)
{
    unsigned char i;
    unsigned char crc = 0x00;

    while (len--)
    {
        crc ^= *ptr++;
        for (i = 8; i > 0; --i)
        {
            if (crc & 0x80)
                crc = (crc << 1) ^ 0x07;
            else
                crc = (crc << 1);
        }
    }

    return (crc);
}

static int32_t Dbattery_Read_Bat_Inf(uint8_t *data)
{
    Device_Write(VHW_IRQ_BAT, NULL, 0, PIN_MODE_OD_DRIVE);
    Device_Write(VHW_IRQ_BAT, NULL, 0, 0);
    Device_DelayMs(6);

    int32_t ret = 1;
    uint8_t ori_data[18] = {IIC_ADDR_BAT << 1, CMD_READ_BAT_INF, (IIC_ADDR_BAT << 1) | 1};
    if (Device_Write(VHW_IIC_BAT, &ori_data[1], 1, IIC_ADDR_BAT) == 0)
    {
        ret = Device_Read(VHW_IIC_BAT, &ori_data[3], 15, IIC_ADDR_BAT);
    }

    Device_Write(VHW_IRQ_BAT, NULL, 0, 1);
    Device_Write(VHW_IRQ_BAT, NULL, 0, PIN_MODE_INPUT_PULLUP);

    /* crc校验 */
    if (ret == 0)
    {
        uint8_t crc = crc8_cal(ori_data, 17);
        if (crc != ori_data[17])
        {
            DBATTERY_LOG("crc err\r\n");
            ret = 2;
        }
        else
        {
            memcpy(data, &ori_data[3], 14);
        }
    }
    else
    {
        DBATTERY_LOG("iic communication  err\r\n");
    }

    return ret;
}

static void Dbattery_Process(void)
{
    Bat_Info_t bat_inf;
    static DbatteryMsg_t lastBattery = {0, 0};
    if (Dbattery_Read_Bat_Inf((uint8_t *)&bat_inf) == 0)
    {
        bat_inf.temp_s = OSAL_SWAP16(bat_inf.temp_s);
        bat_inf.temp_b = OSAL_SWAP16(bat_inf.temp_b);
        bat_inf.vol_s = OSAL_SWAP16(bat_inf.vol_s);
        bat_inf.vol_b = OSAL_SWAP16(bat_inf.vol_b);
        bat_inf.bat_s = OSAL_SWAP16(bat_inf.bat_s);
        bat_inf.bat_b = OSAL_SWAP16(bat_inf.bat_b);

        batMsg.battery_s = (uint8_t)bat_inf.bat_s;
        batMsg.battery_b = (uint8_t)bat_inf.bat_b;
        if (batMsg.battery_s != lastBattery.battery_s || batMsg.battery_b != lastBattery.battery_b)
        {
            lastBattery.battery_s = batMsg.battery_s;
            lastBattery.battery_b = batMsg.battery_b;
            DBATTERY_LOG("vol : %dmV %dmV, bat : %d%% %d%%\r\n", bat_inf.vol_s, bat_inf.vol_b, bat_inf.bat_s, bat_inf.bat_b);
            OSAL_MessagePublish(&batMsg, sizeof(DbatteryMsg_t));
        }
    }
}

static ErrorStatus Dbattery_Get(DbatteryMsg_t *bat)
{
    memcpy((uint8_t *)bat, (uint8_t *)&batMsg, sizeof(DbatteryMsg_t));
    return SUCCESS;
}

/**
  * @brief  Battery任务函数
  *
  * @note   1.任务函数内不能写阻塞代码
  *         2.任务函数每次运行只处理一个事件
  *         
  * @param  event：当前任务的所有事件
  *
  * @return 返回未处理的事件
  */
static uint32_t Dbattery_Task(uint32_t event)
{
    /* 系统启动事件 */
    if (event & EVENT_SYS_START)
    {
        DBATTERY_LOG("Dbattery task start\r\n");
        OSAL_EventRepeatCreate(COMP_DBATTERY, EVENT_BATTERY_UPDATE, BATTERY_UPDATE_EVT_PROC_CYCLE, EVT_PRIORITY_LOW);

        /* 注册对外开放的API接口 */
        SYS_API(Dbattery_Get);

        return (event ^ EVENT_SYS_START);
    }

    /* 系统休眠事件 */
    if (event & EVENT_SYS_SLEEP)
    {
        OSAL_EventDelete(COMP_DBATTERY, EVENT_BATTERY_UPDATE);
        return (event ^ EVENT_SYS_SLEEP);
    }

    /* 电池电量更新事件 */
    if (event & EVENT_BATTERY_UPDATE)
    {
        Dbattery_Process();
        return (event ^ EVENT_BATTERY_UPDATE);
    }
    return 0;
}
COMPONENT_TASK_EXPORT(COMP_DBATTERY, Dbattery_Task, 0);
